package com.kirk.cts.core.runcycle;

import com.kirk.cts.core.launcher.ILauncher;
import com.kirk.cts.core.launcher.SpringLauncherImpl;
import com.kirk.cts.core.runcycle.schedule.ScheduleEnum;
import com.kirk.cts.core.context.CrawlerToolContextData;
import com.kirk.cts.core.loader.*;
import com.kirk.cts.core.runcycle.schedule.Schedule;
import org.apache.log4j.Logger;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * <p> CrawlerToolRunCycleManager.java </p>
 *
 * @version 1.0.0
 * @Author kirkliu
 * @Date 2020-08-29 22:25
 * @Description CrawlerTool 运行周期管理类
 */
public class CrawlerToolRunCycleManager implements ICrawlerToolRunCycle {
    protected Logger logger = Logger.getLogger(this.getClass());

    /**
     * spring容器中注册了的所有Schedule
     */
    private TreeMap<Enum<ScheduleEnum>, Schedule> scheduleTreeMap;

    /**
     * 当前运行周期的计划
     */
    private Schedule currentSchedule = null;

    public CrawlerToolRunCycleManager() {
        //设置自身引用到CrawlerToolContextData
        CrawlerToolContextData.getInstance().setCrawlerToolRunCycle(this);
    }

    /**
     * 初始化计划MAP
     */
    private void initScheduleMap() {
        Map<String, Schedule> map = CrawlerToolContextData.getInstance().getApplicationContext().getBeansOfType(Schedule.class);
        scheduleTreeMap = new TreeMap<Enum<ScheduleEnum>, Schedule>();
        if (!CollectionUtils.isEmpty(map)) {
            for (Map.Entry<String, Schedule> entry : map.entrySet()) {
                Schedule schedule = entry.getValue();
                scheduleTreeMap.put(schedule.getSchedule(), schedule);
            }
        } else {
            logger.error("没有在Spring容器中找到P2Phase的bean!");
        }
    }

    /**
     * 初始化Spring容器
     */
    private void initSpringContext() {
        logger.info("开始初始化Spring容器.....");
        long startDate = System.currentTimeMillis();
        ILauncher launcher = new SpringLauncherImpl();
        launcher.launch();
        logger.info("Spring容器初始化成功,消耗时间:" + (System.currentTimeMillis() - startDate) / 1000 + "s");
    }

    /**
     * 初始化系统环境变量配置
     */
    private void initEnv() {
        logger.info("" + Locale.getDefault());
        //国际化
        LanguageLoader.setLanguage(Locale.getDefault());
        //图标
        ImageLoader.setLanguage(Locale.getDefault());
        //异常
        ExceptionLoader.setLanguage(Locale.getDefault());
        //加载插件
        PluginsLoader.loadPlugins();
        //加载配置参数
        ConfigLoader.loadConfig();
    }


    @Override
    public void start() {
        initEnv();
        //启动spring容器
        initSpringContext();
        //加载Schedulemap
        initScheduleMap();
        //执行计划
        List<ScheduleEnum> states = new ArrayList<>(2);
        states.add(ScheduleEnum.RUN);
        states.add(ScheduleEnum.START);
        executeSchedule(states);

    }

    /**
     * 执行计划
     */
    private void executeSchedule(List<ScheduleEnum> states) {
        logger.info("执行计划计划:" + states.toString());
        for (Map.Entry<Enum<ScheduleEnum>, Schedule> entry : scheduleTreeMap.entrySet()) {
            logger.info(entry.getValue());
            //取得运行计划
            Schedule schedule = entry.getValue();
            try {
                if (null != schedule && states.contains(schedule.getSchedule())) {
                    logger.info("执行当前运行计划:" + schedule.getSchedule());
                    //执行当前运行计划
                    schedule.execute();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
                //this.exceptionProcessor.handleException(phase, ex);
            }
            //将当前阶段赋予全局变量
            currentSchedule = schedule;
        }
    }

    @Override
    public void end() {
        synchronized (CrawlerToolContextData.getInstance().getCrawlerToolTheadLock()) {
            CrawlerToolContextData.getInstance().getCrawlerToolTheadLock().notify();
        }
        //执行计划
        List<ScheduleEnum> states = new ArrayList<>(1);
        states.add(ScheduleEnum.SHUTDOWN);
        executeSchedule(states);
    }


    @Override
    public Schedule getCurrentSchedule() {
        return this.currentSchedule;
    }

}
